# Interned String in Java

์ž๋ฐ”(Java)์˜ ๋ฌธ์ž์—ด(String)์€ ๋ถˆ๋ณ€(immutable)ํ•˜๋‹ค. String์˜ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ์„ ํ•˜๋ฉด ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ํ•จ์ˆ˜์˜ ๊ฒฐ๊ณผ๋กœ ํ•ด๋‹น ๊ฐ์ฒด๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ•ญ์ƒ ๊ทธ๋Ÿฐ ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์•„๋ž˜ ์˜ˆ๋ฅผ ๋ณด์ž.

public void func() {
    String haribo1st = new String("HARIBO");
    String copiedHaribo1st = haribo1st.toUpperCase();
    System.out.println(haribo1st == copiedHaribo1st);   
}

"HARIBO"๋ผ๋Š” ๋ฌธ์ž์—ด์„ ์„ ์–ธํ•œ ํ›„, toUpperCase()๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์žˆ๋‹ค. ์•ž์„œ ๋ง๋Œ€๋กœ ๋ถˆ๋ณ€ ๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— toUpperCase()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๊ธฐ์กด ๊ฐ์ฒด์™€ ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ๋‚˜์™€์•ผ ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ==์œผ๋กœ ๋น„๊ต๋ฅผ ํ•ด๋ณด๋ฉด true๋กœ ์„œ๋กœ ๊ฐ™์€ ๊ฐ’์ด๋‹ค. ๊ทธ ์ด์œ ๋Š” toUpperCase() ํ•จ์ˆ˜์˜ ๋กœ์ง ๋•Œ๋ฌธ์ด๋‹ค. ํ•ด๋‹น ํ•จ์ˆ˜๋Š” lower case์˜ ๋ฌธ์ž๊ฐ€ ๋ฐœ๊ฒฌ๋˜์ง€ ์•Š์œผ๋ฉด ๊ธฐ์กด์˜ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ์ƒ์„ฑ์ž(new String("HARIBO"))๋ฅผ ์ด์šฉํ•ด์„œ ๋ฌธ์ž์—ด์„ ์ƒ์„ฑํ•˜๋ฉด "HARIBO"์œผ๋กœ ์„ ์–ธํ•œ ๊ฐ์ฒด์™€ ๊ฐ™์€ ๊ฐ์ฒด์ผ๊นŒ? ์•„๋‹ˆ๋‹ค. ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์„ ์–ธํ•˜๊ฒŒ ๋˜๋ฉด ๊ฐ™์€ ๋ฌธ์ž์—ด์„ ๊ฐ€์ง„ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค. ์ฆ‰, ํž™(heap)์— ์ƒˆ๋กœ์šด ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

public void func() {
    String haribo1st = new String("HARIBO");
    String haribo3rd = "HARIBO";
    System.out.println(haribo1st == haribo3rd);
    System.out.println(haribo1st.equals(haribo3rd));
}

์œ„์˜ ์˜ˆ์ œ๋ฅผ ๋ณด๋ฉด == ๋น„๊ต์˜ ๊ฒฐ๊ณผ๋Š” false์ด์ง€๋งŒ equals()์˜ ๊ฒฐ๊ณผ๋Š” true์ด๋‹ค. ๋‘ ๊ฐœ์˜ ๋ฌธ์ž์—ด์€ ๊ฐ™์€ ๊ฐ’์„ ๊ฐ€์ง€์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ๋‹ค๋ฅธ ๊ฐ์ฒด์ด๋‹ค. ๋‘ ๊ฐ์ฒด์˜ hash ๊ฐ’์„ ๋น„๊ตํ•ด๋ณด๋ฉด ํ™•์‹คํ•˜๊ฒŒ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

public void func() {
    String haribo3rd = "HARIBO";
    String haribo4th = String.valueOf("HARIBO");
        
    System.out.println(haribo3rd == haribo4th);
    System.out.println(haribo3rd.equals(haribo4th));
}

์ด๋ฒˆ์—๋Š” ๋ฆฌํ„ฐ๋Ÿด(literal)๋กœ ์„ ์–ธํ•œ ๊ฐ์ฒด์™€ String.valueOf()๋กœ ๊ฐ€์ ธ์˜จ ๊ฐ์ฒด๋ฅผ ํ•œ๋ฒˆ ์‚ดํŽด๋ณด์ž. valueOf()ํ•จ์ˆ˜๋ฅผ ๋“ค์–ด๊ฐ€๋ณด๋ฉด ์•Œ๊ฒ ์ง€๋งŒ, ์ฃผ์–ด์ง„ ๋งค๊ฐœ ๋ณ€์ˆ˜๊ฐ€ null์ธ์ง€ ํ™•์ธํ•œ ํ›„ null์ด ์•„๋‹ˆ๋ฉด ๋งค๊ฐœ ๋ณ€์ˆ˜์˜ toString()์„ ํ˜ธ์ถœํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ String.toString()์€ this๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ฆ‰, ๋‘ ๊ตฌ๋ฌธ ๋ชจ๋‘ "HARIBO"์ฒ˜๋Ÿผ ๋ฆฌํ„ฐ๋Ÿด ์„ ์–ธ์ด๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ๋ฆฌํ„ฐ๋Ÿด๋กœ ์„ ์–ธํ•œ ๊ฐ์ฒด๋Š” ์™œ ๊ฐ™์€ ๊ฐ์ฒด์ผ๊นŒ?

๋ฐ”๋กœ JVM์—์„œ constant pool์„ ํ†ตํ•ด ๋ฌธ์ž์—ด์„ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋ฆฌํ„ฐ๋Ÿด๋กœ ์„ ์–ธํ•œ ๋ฌธ์ž์—ด์ด constant pool์— ์žˆ์œผ๋ฉด ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ๋ฐ”๋กœ ๊ฐ€์ ธ์˜จ๋‹ค. ๋งŒ์•ฝ pool์— ์—†๋‹ค๋ฉด ์ƒˆ๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ ํ›„, pool์— ๋“ฑ๋กํ•˜๊ณ  ๊ฐ€์ ธ์˜จ๋‹ค. ์ด๋Ÿฌํ•œ ํ”Œ๋กœ์šฐ๋ฅผ ๊ฑฐ์น˜๊ธฐ ๋•Œ๋ฌธ์— "HARIBO"๋กœ ์„ ์–ธํ•œ ๋ฌธ์ž์—ด์€ ๊ฐ™์€ ๊ฐ์ฒด๋กœ ๋‚˜์˜ค๋Š” ๊ฒƒ์ด๋‹ค. String.intern() ํ•จ์ˆ˜๋ฅผ ์ฐธ๊ณ ํ•ด๋ณด์ž.

# References

  • https://www.latera.kr/blog/2019-02-09-java-string-intern/
  • https://blog.naver.com/adamdoha/222817943149
์ตœ์ข… ์ˆ˜์ • : 12/17/2022, 7:23:59 AM